package com.algorithm.sort;

/*
归并排序：
排序原理：
1.尽可能的一组数据拆分成两个元素相等的子组，并对每一个子组继续拆分，直到拆分后的每个子组的元素个数是1为止。
2将相邻的两个子组进行合并成一个有序的大组：
3不断的重复步骤2，直到最终只有一个组为止。
 */
public class Merge {
    //归并排序：
    //辅助数组
    private static Comparable[] assist;

    //对数组排序
    public static void sort(Comparable[] a) {
        //1.初始化铺助数组assist
        assist = new Comparable[a.length];


        //2.定义一个Lo变量和hi变量分别记录数组中最小的索引和最大的索引
        int lo = 0;
        int hi = a.length - 1;

        //3.调用sort重载方法完成数组a中·从索儿lo到索h1的元素的排序
        sort(a, lo, hi);
    }


    //对数组a中lo到hi之间元素排序
    private static void sort(Comparable[] a, int lo, int hi) {
        //安全校验
        if (hi <= lo) {
            return;
        }

        //lo到hi分组
        int mid = lo + (hi - lo) / 2;

        //对每一组排序
        sort(a, lo, mid);
        sort(a, mid + 1, hi);

        //归并
        merge(a, lo, mid, hi);

    }


    //从索引mid+1到索引hi为另一个子组，把数组a中的这两个子组的数据合并成个有序的大组，从索引Io到索引hi
    private static void merge(Comparable[] a, int lo, int mid, int hi) {
        //定义三个指针
        int i = lo;
        int p1 = lo;
        int p2 = mid + 1;

        //遍历，移动p1和p2指针，找出小的，放到对应的索引处
        while (p1 <= mid && p2 <= hi) {
            if (less(a[p1], a[p2])) {
                assist[i++] = a[p1++];
            } else {
                assist[i++] = a[p2++];
            }
        }

        //遍历，如果p1的指针没有走完，那么顺序移动p1指针，把对应的元素放到辆幼数组的对应索引处
        while (p1 <= mid) {
            assist[i++] = a[p1++];
        }

        //遍历，如果p2的指针没有走完，那么顺序移动p2指针，把对应的元素放到辆幼数组的对应索引处
        while (p2 <= hi) {
            assist[i++] = a[p2++];
        }

        //把辅助数组中的元素拷贝到原数组中
        for (i = lo; i <= hi; i++) {
            a[i] = assist[i];
        }
    }


    private static boolean less(Comparable v, Comparable w) {
        return v.compareTo(w) < 0;
    }


    private static void exch(Object[] a, int i, int j) {
        Object t = a[i];
        a[i] = a[j];
        a[j] = t;

    }
}